package com.gdcnano.nanoamp.media.sound.playlist
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import mx.collections.ArrayCollection;
	
	import org.as3commons.lang.IllegalArgumentError;
	
	/**
	 * ABSTRACT playlist class.
	 * Implements common tracklist operations.
	 * @author gareevm
	 * 
	 */	
	public class AbstractPlaylist extends EventDispatcher implements IPlaylist
	{
		public static const TRACK_CHANGED:String = "trackChanged";
		
		public static const TRACK_NOT_IN_PLAYLIST:String = "trackNotInPlaylist";
		
		public static const TRACK_IS_EMPTY:String = "trackIsEmpty";
		
		public static const TRACKLIST_IS_EMPTY:String = "tracklistIsEmpty";
		
		private static const DEFAULT_PLAYLIST_NAME:String = "Playlist";
		
		protected var _tracklist:ArrayCollection;
		
		private var _currentTrack:ITrack;
		
		private var _canPlayNextTrack:Boolean = false;
		
		private var _canPlayPreviousTrack:Boolean = false;
		
		[Bindable(event="trackChanged")]
		public function get canPlayNextTrack():Boolean
		{
			return _canPlayNextTrack;
		}

		public function set canPlayNextTrack(value:Boolean):void {}
		
		[Bindable(event="trackChanged")]
		public function get canPlayPreviousTrack():Boolean
		{
			return _canPlayPreviousTrack;
		}
		
		[Bindable(event="trackChanged")]
		/**
		 * @inheritDoc
		 *
		 */
		public function get currentTrackIndex():int
		{
			return tracklist.getItemIndex(_currentTrack);
		}
		
		public function set currentTrackIndex(value:int):void {}
		
		public function set canPlayPreviousTrack(value:Boolean):void {}
		
		/**
		 * Abstract class can not be instantiated
		 * 
		 */
		public function AbstractPlaylist()
		{
			_tracklist = new ArrayCollection();
		}
		
		public function addTrack(track:ITrack):void
		{
			_tracklist.addItem(track);
		}
		
		public function get currentTrack():ITrack
		{
			return _currentTrack;
		}
		
		public function set currentTrack(track:ITrack):void
		{
			if (tracklist.length > 0)
			{
				if (tracklist.contains(track))
				{
					_currentTrack = track;
					checkFirstLastTrack();
					dispatchEvent(new Event(TRACK_CHANGED));
				}
				else
				{
					// TODO: write listener & handler
					dispatchEvent(new Event(TRACK_NOT_IN_PLAYLIST));
				}
			}
			else
			{
				// TODO: write listener & handler
				dispatchEvent(new Event(TRACKLIST_IS_EMPTY));
			}
		}
		
		public function clearCurrentTrack():void
		{
			_currentTrack = null;
			dispatchEvent(new Event(TRACK_IS_EMPTY));
		}
		
		/**
		 * @inheritDoc
		 *
		 */
		public function nextTrack():void
		{
			var nextTrack:ITrack = getNextTrack();
			if (nextTrack)
			{
				currentTrack = nextTrack;
			}
		}
		
		/**
		 * Tries to get next track from tracklist if available
		 * @return next track
		 * 
		 */		
		private function getNextTrack():ITrack
		{
			var nextTrack:ITrack = null;
			if (canPlayNextTrack)
			{
				nextTrack = tracklist.getItemAt(currentTrackIndex + 1) as ITrack;
			}
			return nextTrack;
		}
		
		/**
		 * @inheritDoc
		 */
		public function previousTrack():void
		{
			var previousTrack:ITrack = getPreviousTrack();
			if (previousTrack)
			{
				currentTrack = previousTrack;
			}
		}
			
		
		private function getPreviousTrack():ITrack
		{
			var previousTrack:ITrack = null;
			if (canPlayPreviousTrack)
			{
				previousTrack = tracklist.getItemAt(currentTrackIndex - 1) as ITrack;
			}
			return previousTrack;
		}
		
		public function getRandomTrack():ITrack
		{
			return null;
		}
		
		public function get playlistName():String
		{
			return DEFAULT_PLAYLIST_NAME;
		}
		
		public function removeTrack(track:ITrack):void
		{
			if (tracklist.contains(track))
			{
				_tracklist.removeItemAt(_tracklist.getItemIndex(track));
			}
			else
			{
				dispatchEvent(new Event(TRACK_NOT_IN_PLAYLIST));
			}
		}
		
		public function clear():void
		{
			clearCurrentTrack();
			tracklist.removeAll();
		}
		
		/**
		 * @inheritDoc
		 *
		 */
		public function get tracklist():ArrayCollection
		{
			return _tracklist;
		}
		
		public function setPlaylistData(data:Object):Boolean
		{
			throw new IllegalArgumentError("Abstract method");
		}
		
		/**
		 * Checks if playlist can play next/previous tracks 
		 * 
		 */
		private function checkFirstLastTrack():void
		{
			_canPlayNextTrack = (currentTrackIndex < (tracklist.length - 1));
			
			_canPlayPreviousTrack = (currentTrackIndex > 0);
		}
	}
}